#include <iostream>
#include <iomanip>

#include "TFile.h"
#include "TTree.h"
#include "TH1F.h"
#include "TH2F.h"

#include "BuiltEvent.hh"

using namespace std;

ClassImp(BuiltEvent)
ClassImp(AdcData)
ClassImp(DgfData)

int main(int argc, char* argv[])
{
  if(argc <3 || argc >4)
    {
      cout<<"usage: BuiltEventHistograms <input file> <output file> <nof events (optional)>"<<endl;
      return 1;
    }
  
  int i,j,k;

  TFile* infile = new TFile(argv[1]);

  if(infile->IsZombie())
    {
      return 2;
    }

  TTree* tr = (TTree*) infile->Get("tr");

  if(tr == NULL)
    {
      cout << "could not find tree tr in file " << infile->GetName() << endl;
      return 3;
    }

  BuiltEvent* event = new BuiltEvent;

  tr->SetBranchAddress("Event",&event);

  TFile* outfile = new TFile(argv[2],"recreate");

  if(outfile->IsZombie())
    {
      return 4;
    }

  //histograms
  //diagnostics
  TH1F* adc = new TH1F("adc","adc",8,-0.5,7.5);
  TH1F* dgf = new TH1F("dgf","dgf",56,-0.5,55.5);
  TH1F* free_dgf = new TH1F("free_dgf","free_dgf",56,-0.5,55.5);
  TH1F* one_dgf = new TH1F("one_dgf","one_dgf",56,-0.5,55.5);
  TH1F* two_dgf = new TH1F("two_dgf","two_dgf",56,-0.5,55.5);

  //time differences
  TH1F* tdiff = new TH1F("tdiff","tdiff",2000,-1000,1000);
  TH1F* part_tdiff = new TH1F("part_tdiff","part_tdiff",2000,-1000,1000);
  TH1F* gam_tdiff = new TH1F("gam_tdiff","gam_tdiff",2000,-100,100);

  //gamma-spectra
  TH1F* E_gam[55][4];
  for(i = 0; i < 55; i++)
    for(j = 0; j < 4; j++)
      E_gam[i][j] = new TH1F(Form("E_gam_%d_%d",i,j),Form("E_gam_%d_%d",i,j),65536,0,65536);

  //particle-spectra
  TH1F* E_part[7][32];
  for(i = 0; i < 7; i++)
    for(j = 0; j < 32; j++)
      E_part[i][j] = new TH1F(Form("E_part_%d_%d",i,j),Form("E_part_%d_%d",i,j),4096,0,4096);

  TH2F* CD_energy_id[4];
  for(i = 0; i < 4; i++)
    {
      CD_energy_id[i] = new TH2F(Form("CD_energy_id_%d",i),Form("CD_energy_id_%d",i),4096,0,4096,4096,0,4096);
    }

  TH2F* Strip_vs_Rear[8][16];
  TH1F* Rear_ForStrip[8][16];
  for(i = 0; i < 8; i++)
    for(j = 0; j < 16; j++)
      {
	Strip_vs_Rear[i][j] = new TH2F(Form("Strip_vs_Rear_%d_%d",i,j),Form("Strip_vs_Rear_%d_%d",i,j),400,0,4000,400,0,4000);
	Rear_ForStrip[i][j] = new TH1F(Form("Rear%d_ForStrip%d",i,j), Form("Rear%d_ForStrip%d",i,j),4096,0,4096);
      }

  TH2F* Rear_vs_StripNr[8];
  for(i = 0; i < 8; i++){
    Rear_vs_StripNr[i] = new TH2F(Form("Rear_vs_StripNr_%d",i),Form("Rear_vs_StripNr_%d",i),16,0,16,400,0,4000);
  }
  TH2F* Forward_T_vs_L = new TH2F("Forward_T_vs_L","Forward_T_vs_L",400,0,4000,400,0,4000);
  TH2F* Forward_B_vs_R = new TH2F("Forward_B_vs_R","Forward_B_vs_R",400,0,4000,400,0,4000);  
  TH2F* Backward_T_vs_L = new TH2F("Backward_T_vs_L","Backward_T_vs_L",400,0,4000,400,0,4000);
  TH2F* Backward_B_vs_R = new TH2F("Backward_B_vs_R","Backward_B_vs_R",400,0,4000,400,0,4000);

  TH2F *HitinB04[16];
  TH2F *NoHitinB04[16];
  for(i=0; i<16; i++){
    HitinB04[i] = new TH2F(Form("HitinB04_%d",i),Form("HitinB04_%d",i),512,0,4096,512,0,4096);
    NoHitinB04[i] = new TH2F(Form("NoHitinB04_%d",i),Form("NoHitinB04_%d",i),512,0,4096,512,0,4096);
  }

  Double_t nentries = tr->GetEntries();
  Int_t nbytes = 0;
  Int_t status;
  vector<int> DgfModule;

  vector<unsigned short> cd_energy[4];
  vector<unsigned short> cd_id[4];

  unsigned short rear[8];
  unsigned short strip[8][16];

  unsigned short strip1, strip2;
  if(argc==4)
    nentries =atoi(argv[3]);
  for(i=0; i<nentries;i++) 
    {
      status = tr->GetEvent(i);
      if(status == -1)
	{
	  cerr<<"Error occured, couldn't read entry "<<i<<" from tree "<<tr->GetName()<<" in file "<<infile->GetName()<<endl;
	  return 5;
	}
      else if(status == 0)
	{
	  cerr<<"Error occured, entry "<<i<<" in tree "<<tr->GetName()<<" in file "<<infile->GetName()<<" doesn't exist"<<endl;
	  return 6;
	}
      nbytes += status;
      
      DgfModule.clear();

      for(j = 0; j < 4; j++)
	{
	  cd_energy[j].clear();
	  cd_id[j].clear();
	}

      for(j = 0; j < 8; j++)
	{
	  rear[j] = 0;
	  for(k = 0; k < 16; k++)
	    {
	      strip[j][k] = 0;
	    }
	}

      for(j = 0; j < event->NumberOfDgfs(); j++)
	{
	  for(k = 0; k < DgfModule.size(); k++)
	    {
	      if(event->Dgf(j)->ModuleNumber() == DgfModule[k])
		break;
	    }
	  if(k == DgfModule.size())
	    DgfModule.push_back(event->Dgf(j)->ModuleNumber());
	}

	  	  
      for(j = 0; j < event->NumberOfAdcs(); j++)
	{
	  for(k = 0; k < event->NumberOfDgfs(); k++)
	    {
	      tdiff->Fill(event->Adc(j)->Time() - event->Dgf(k)->Time());
	    }
	}

      adc->Fill(event->NumberOfAdcs());
      dgf->Fill(DgfModule.size());

      if(event->NumberOfAdcs() == 0)
	{
	  free_dgf->Fill(DgfModule.size());

	  for(j = 0; j < event->NumberOfDgfs(); j++)
	    {
	      for(k = j+1; k < event->NumberOfDgfs(); k++)
		{
		  gam_tdiff->Fill(event->Dgf(j)->Time() - event->Dgf(k)->Time());
		}
	    }
	}

      if(event->NumberOfAdcs() == 3 || event->NumberOfAdcs() == 4)
	{
	  one_dgf->Fill(DgfModule.size());
	}

      if(event->NumberOfAdcs() == 6 || event->NumberOfAdcs() == 7)
	{
	  two_dgf->Fill(DgfModule.size());
	  part_tdiff->Fill(event->Adc(0)->Time()-event->Adc(3)->Time());
	}

      for(j = 0; j < event->NumberOfDgfs(); j++)
	{
	  if(0 <= event->Dgf(j)->ModuleNumber() && event->Dgf(j)->ModuleNumber() < 55
	     && 0 <= event->Dgf(j)->Channel() && event->Dgf(j)->Channel() < 4)
	    {
	      E_gam[event->Dgf(j)->ModuleNumber()][event->Dgf(j)->Channel()]->Fill(event->Dgf(j)->Energy());
	    }
	  else
	    {
	      cout<<"["<<event->Dgf(j)->ModuleNumber()<<"]["<<event->Dgf(j)->Channel()<<"] = "<<event->Dgf(j)->Energy()<<endl;
	    }
	}

      strip1 = 0;
      strip2 = 0;
      //cout << "event->NumberOfAdcs() " << event->NumberOfAdcs() << endl;
      for(j = 0; j < event->NumberOfAdcs(); j++)
	{
	  //cout << "#ch: " << event->Adc(j)->SubEvent()->AdcChannel().size() << "#val: " << event->Adc(j)->SubEvent()->AdcValue().size() << endl;
	  for(k = 0; k < event->Adc(j)->SubEvent()->Size(); k++)
	    {
	      if(0 <= event->Adc(j)->ModuleNumber() && event->Adc(j)->ModuleNumber() < 7
		 && 0 <= event->Adc(j)->SubEvent()->AdcChannel(k) && event->Adc(j)->SubEvent()->AdcChannel(k) < 32)
		{
		  //cout << "Hit in " << event->Adc(j)->ModuleNumber() << " " << event->Adc(j)->SubEvent()->AdcChannel(k) << " with value " <<event->Adc(j)->SubEvent()->AdcValue(k) << endl;
		  E_part[event->Adc(j)->ModuleNumber()][event->Adc(j)->SubEvent()->AdcChannel(k)]->Fill(event->Adc(j)->SubEvent()->AdcValue(k));
		}
	      else
		{
		  cout<<"["<<event->Adc(j)->ModuleNumber()<<"]["<<event->Adc(j)->SubEvent()->AdcChannel(k)<<"] = "<<event->Adc(j)->SubEvent()->AdcValue(k)<<endl;
		}

	      if(event->Adc(j)->ModuleNumber() == 2){ //first rear and cd module
		switch(event->Adc(j)->SubEvent()->AdcChannel(k)){
		case 0:// FT deltaE rear
		  rear[0] = event->Adc(j)->SubEvent()->AdcValue(k);
		  break;
		case 2:// BT deltaE rear
		  rear[4] = event->Adc(j)->SubEvent()->AdcValue(k);
		  break;
		case 4:// FL deltaE rear
		  rear[1] = event->Adc(j)->SubEvent()->AdcValue(k);
		  break;
		case 6:// BL deltaE rear
		  rear[5] = event->Adc(j)->SubEvent()->AdcValue(k);
		  break;
		default:
		  break;
		}
	      }
	      else if(event->Adc(j)->ModuleNumber() == 5){ //second rear and cd module
		switch(event->Adc(j)->SubEvent()->AdcChannel(k)){
		case 0:// FB deltaE rear
		  rear[2] = event->Adc(j)->SubEvent()->AdcValue(k);
		  break;
		case 2:// BB deltaE rear
		  rear[6] = event->Adc(j)->SubEvent()->AdcValue(k);
		  break;
		case 4:// FR deltaE rear
		  rear[3] = event->Adc(j)->SubEvent()->AdcValue(k);
		  break;
		case 6:// BR deltaE rear
		  rear[7] = event->Adc(j)->SubEvent()->AdcValue(k);
		  break;
		default:
		  break;
		}
	      }
	      else if(event->Adc(j)->ModuleNumber() == 0){ //strips of T 
		if(event->Adc(j)->SubEvent()->AdcChannel(k) < 16){ // FT deltaE
		  strip[0][event->Adc(j)->SubEvent()->AdcChannel(k)] = event->Adc(j)->SubEvent()->AdcValue(k);
		}
		else{ // BT deltaE
		  strip[4][event->Adc(j)->SubEvent()->AdcChannel(k)-16] = event->Adc(j)->SubEvent()->AdcValue(k);
		}
	      }
	      else if(event->Adc(j)->ModuleNumber() == 1){ //strips of L
		if(event->Adc(j)->SubEvent()->AdcChannel(k) < 16){ // FL deltaE
		  strip[1][event->Adc(j)->SubEvent()->AdcChannel(k)] = event->Adc(j)->SubEvent()->AdcValue(k);
		}
		else{ // BL deltaE
		  strip[5][event->Adc(j)->SubEvent()->AdcChannel(k)-16] = event->Adc(j)->SubEvent()->AdcValue(k);
		}
	      }
	      else if(event->Adc(j)->ModuleNumber() == 3){ //strips of B
		if(event->Adc(j)->SubEvent()->AdcChannel(k) < 16){ // FB deltaE
		  strip[2][event->Adc(j)->SubEvent()->AdcChannel(k)] = event->Adc(j)->SubEvent()->AdcValue(k);
		}
		else{ // BT deltaE
		  strip[6][event->Adc(j)->SubEvent()->AdcChannel(k)-16] = event->Adc(j)->SubEvent()->AdcValue(k);
		}
	      }
	      else if(event->Adc(j)->ModuleNumber() == 4){ //strips of R
		if(event->Adc(j)->SubEvent()->AdcChannel(k) < 16){ // FR deltaE
		  strip[3][event->Adc(j)->SubEvent()->AdcChannel(k)] = event->Adc(j)->SubEvent()->AdcValue(k);
		}
		else{ // BR deltaE
		  strip[7][event->Adc(j)->SubEvent()->AdcChannel(k)-16] = event->Adc(j)->SubEvent()->AdcValue(k);
		}
		if(event->Adc(j)->SubEvent()->AdcChannel(k) == 8)
		  strip1 = event->Adc(j)->SubEvent()->AdcValue(k);
		else if(event->Adc(j)->SubEvent()->AdcChannel(k) == 10)
		  strip2 = event->Adc(j)->SubEvent()->AdcValue(k);
	      }
	      
	      if(event->Adc(j)->ModuleNumber() == 2)
		{
		  if(event->Adc(j)->SubEvent()->AdcChannel(k) == 8)
		    {
		      cd_energy[0].push_back(event->Adc(j)->SubEvent()->AdcValue(k));
		    }
		  else if(event->Adc(j)->SubEvent()->AdcChannel(k) == 9)
		    {
		      cd_id[0].push_back(event->Adc(j)->SubEvent()->AdcValue(k));
		    }
		  else if(event->Adc(j)->SubEvent()->AdcChannel(k) == 12)
		    {
		      cd_energy[1].push_back(event->Adc(j)->SubEvent()->AdcValue(k));
		    }
		  else if(event->Adc(j)->SubEvent()->AdcChannel(k) == 13)
		    {
		      cd_id[1].push_back(event->Adc(j)->SubEvent()->AdcValue(k));
		    }
		}
	      else if(event->Adc(j)->ModuleNumber() == 5)
		{
		  if(event->Adc(j)->SubEvent()->AdcChannel(k) == 8)
		    {
		      cd_energy[2].push_back(event->Adc(j)->SubEvent()->AdcValue(k));
		    }
		  else if(event->Adc(j)->SubEvent()->AdcChannel(k) == 9)
		    {
		      cd_id[2].push_back(event->Adc(j)->SubEvent()->AdcValue(k));
		    }
		  else if(event->Adc(j)->SubEvent()->AdcChannel(k) == 12)
		    {
		      cd_energy[3].push_back(event->Adc(j)->SubEvent()->AdcValue(k));
		    }
		  else if(event->Adc(j)->SubEvent()->AdcChannel(k) == 13)
		    {
		      cd_id[3].push_back(event->Adc(j)->SubEvent()->AdcValue(k));
		    }
		}
	    }
	}//numberofadcs

      Forward_T_vs_L->Fill(rear[1], rear[0]);
      Forward_B_vs_R->Fill(rear[3], rear[2]);

      Backward_T_vs_L->Fill(rear[5], rear[4]);
      Backward_B_vs_R->Fill(rear[7], rear[6]);

      for(j = 0; j < 4; j++)
	{
	  for(k = 0; k < cd_energy[j].size(); k++)
	    {
	      CD_energy_id[j]->Fill(cd_id[j][k], cd_energy[j][k]);
	    }
	}

      for(j = 0; j < 8; j++)
	{
	  for(k = 0; k < 16; k++)
	    {
	      if(rear[j] > 0 || strip[j][k] > 0)
		{
		  Strip_vs_Rear[j][k]->Fill(rear[j],strip[j][k]);
		}
	    }
	}
      int maxstrip_nr;
      double maxstrip_en;
      for(j = 0; j < 8; j++){
	maxstrip_nr=-1;
	maxstrip_en=0.;
	if(rear[j] > 0){
	  for(k = 0; k < 16; k++){
	    if(strip[j][k]>maxstrip_en){
	      maxstrip_en=strip[j][k];
	      maxstrip_nr=k;
	    }
	  }
	  Rear_vs_StripNr[j]->Fill(maxstrip_nr,rear[j]);
	  Rear_ForStrip[j][maxstrip_nr]->Fill(rear[j]);
	}
	if((j==4)&&(maxstrip_nr==4)){ // hit in B04
	  for(k=0; k<16; k++){
	    if(rear[4]>1000)
	      HitinB04[k]->Fill(strip[4][4],strip[4][k]);
	    else if(rear[4]<999)
	      NoHitinB04[k]->Fill(strip[4][4],strip[4][k]);

	  }
	}
      }

      if(i%1000 == 0)
	{
	  cout<<setw(5)<<setiosflags(ios::fixed)<<setprecision(1)<<(100.*i)/nentries<<" % done\r"<<flush;
	}
	 }
  
  tdiff->Write("",TObject::kOverwrite);
  adc->Write("",TObject::kOverwrite);
  dgf->Write("",TObject::kOverwrite);
  free_dgf->Write("",TObject::kOverwrite);
  one_dgf->Write("",TObject::kOverwrite);
  two_dgf->Write("",TObject::kOverwrite);
  gam_tdiff->Write("",TObject::kOverwrite);
  part_tdiff->Write("",TObject::kOverwrite);
  for(i = 0; i < 55; i++)
    for(j = 0; j < 4; j++)
      E_gam[i][j]->Write("",TObject::kOverwrite);

  //partice-spektra
  for(i = 0; i < 7; i++)
    for(j = 0; j < 32; j++)
      E_part[i][j]->Write("",TObject::kOverwrite);

  for(i = 0; i < 4; i++)
    CD_energy_id[i]->Write("",TObject::kOverwrite);

  for(i = 0; i < 8; i++)
    for(j = 0; j < 16; j++)
      {
	Strip_vs_Rear[i][j]->Write("",TObject::kOverwrite);
	Rear_ForStrip[i][j]->Write("",TObject::kOverwrite);
      }
  for(i = 0; i < 8; i++)
    Rear_vs_StripNr[i]->Write("",TObject::kOverwrite);

  Forward_T_vs_L->Write("",TObject::kOverwrite);
  Forward_B_vs_R->Write("",TObject::kOverwrite);
  Backward_T_vs_L->Write("",TObject::kOverwrite);
  Backward_B_vs_R->Write("",TObject::kOverwrite);

  for(i=0; i<16; i++){
    HitinB04[i]->Write("",TObject::kOverwrite);
    NoHitinB04[i]->Write("",TObject::kOverwrite);
  }


  infile->Close();
  outfile->Close();

  return 0;
}
